---
title: 聚合函数
description: 对一组数据进行汇总的函数
---


## 聚集函数

SQL 中的聚集函数一共包括 5 个，可以求某列的最大值、最小值、平均值等。
<img src="https://wkq-img.oss-cn-chengdu.aliyuncs.com/20241127233902.png"/>

```sql title='查询最大生命值大于 6000 的英雄数量'
SELECT COUNT(*) FROM heros WHERE hp_max > 6000
```


```sql title='查询最大生命值大于 6000，且有次要定位的英雄数量，需要使用 COUNT 函数'
SELECT COUNT(role_assist) FROM heros WHERE hp_max > 6000
```

需要说明的是，有些英雄没有次要定位，即 role_assist 为 NULL，这时COUNT(role_assist)会忽略值为 NULL 的数据行，而 COUNT(*) 只是统计数据行数，不管某个字段是否为 NULL。


求总数量，使用的是 COUNT(*) 函数, 求平均值、最大值、最小值，以及所有值的和，我们分别使用的是 AVG、MAX、MIN 和 SUM 函数。





## 对数据进行分组，并进行聚集统计

在统计的时候，需要先对数据按照不同的数值进行分组，然后对这些分好的组进行聚集统计。

对数据进行分组，需要使用 GROUP BY 子句。

```sql title='按照英雄的主要定位进行分组，并统计每组的英雄数量'
SELECT COUNT(*), role_main FROM heros GROUP BY role_main
```
```sql title= '对英雄按照次要定位进行分组，并统计每组英雄的数量。'
SELECT COUNT(*), role_assist FROM heros GROUP BY role_assist
```

如果字段为 NULL，也会被列为一个分组。

也可以使用多个字段进行分组，这就相当于把这些字段可能出现的所有的取值情况都进行分组。

```sql title='按照英雄的主要定位、次要定位进行分组，查看这些英雄的数量，并按照这些分组的英雄数量从高到低进行排序'
SELECT COUNT(*) as num, role_main, role_assist FROM heros GROUP BY role_main, role_assist ORDER BY num DESC
```

## 使用 HAVING 过滤分组

当创建出很多分组的时候，有时候就需要对分组进行过滤。但并不是使用 WHERE 字句，而是使用 HAVING 。

HAVING 的作用和 WHERE 一样，都是起到过滤的作用，只不过 WHERE 是用于数据行，而 HAVING 则作用于分组。

```sql title='按照英雄的主要定位、次要定位进行分组，并且筛选分组中英雄数量大于 5 的组，最后按照分组中的英雄数量从高到低进行排序'
SELECT COUNT(*) as num, role_main, role_assist FROM heros GROUP BY role_main, role_assist HAVING num > 5 ORDER BY num DESC
```

HAVING 支持所有 WHERE 的操作，因此所有需要 WHERE 子句实现的功能，你都可以使用 HAVING 对分组进行筛选。

```sql title='筛选最大生命值大于 6000 的英雄，按照主要定位、次要定位进行分组，并且显示分组中英雄数量大于 5 的分组，按照数量从高到低进行排序。'
SELECT COUNT(*) as num, role_main, role_assist FROM heros WHERE hp_max > 6000 GROUP BY role_main, role_assist HAVING num > 5 ORDER BY num DESC
```

## 练习
1. 筛选最大生命值大于 6000 的英雄，按照主要定位进行分组，选择分组英雄数量大于 5 的分组，按照分组英雄数从高到低进行排序，并显示每个分组的英雄数量、主要定位和平均最大生命值。
2. 筛选最大生命值与最大法力值之和大于 7000 的英雄，按照攻击范围来进行分组，显示分组的英雄数量，以及分组英雄的最大生命值与法力值之和的平均值、最大值和最小值，并按照分组英雄数从高到低进行排序，其中聚集函数的结果包括小数点后两位。


